var LLParser = require('./LLParser');
var htmlParser = require('./htmlParser');
var expParser = require('./expParser');
var instruct = require('./instruct');
var STRING_ESCAPE_REGEXP = require('./StringEscape').STRING_ESCAPE_REGEXP;
var STRING_ESCAPE_MAP = require('./StringEscape').STRING_ESCAPE_MAP;
var RUNTIME_NAMES = require('./StringEscape').RUNTIME_NAMES;
exports.LLParser = LLParser;
exports.htmlParser = htmlParser;
exports.expParser = expParser;
var A = RUNTIME_NAMES.TOP_SCOPE + ',' + RUNTIME_NAMES.SUB_SCOPE + ',' + RUNTIME_NAMES.CALLER;
var c = RUNTIME_NAMES.MEMBER + ',' + RUNTIME_NAMES.CALL + ',' + RUNTIME_NAMES.METHODS;
var h = function (e) {
    return e.replace(/-([a-z])/g, function (e, t) {
        return t.toUpperCase();
    });
};
var u = function (e) {
    return '"' + e.replace(STRING_ESCAPE_REGEXP, function (e) {
        return '\\' + STRING_ESCAPE_MAP[e];
    }) + '"';
};
var p = function (e) {
    return '[' + e.join(',') + ']';
};
var g = function (e) {
    var t = [];
    for (var i in e)
        undefined !== e[i] && (/^[_a-z]+$/i.test(i) ? t.push(i + ':' + e[i]) : t.push(u(i) + ':' + e[i]));
    return '{' + t.join(',') + '}';
};
var _ = function (e, t) {
    var i = e.split(/\{\{(.*?)\}\}/);
    var n = [];
    var a = [];
    var o = null;
    for (var s = 0; s < i.length; s++) {
        var l = i[s];
        if (s % 2) {
            var d = expParser.parse(l);
            o = expParser.lvalueStringify(d, t);
            n.push(expParser.stringify(d, t));
            a.push(d);
        } else
            n.push(u(l));
    }
    if (1 === n.length)
        return { c: n[0] };
    var c = expParser.searchBindingPaths(a, t);
    '""' === n[n.length - 1] && n.pop();
    return 2 === n.length && '""' === n[0] ? {
        c: undefined,
        e: 'function(' + A + '){return ' + n[1] + '}',
        l: o,
        b: c
    } : {
        c: undefined,
        e: 'function(' + A + '){return ' + n.join('+') + '}',
        l: null,
        b: c
    };
};
var f = function (e, t) {
    var i = _(e.c, t);
    i.t = 3;
    i.l = undefined;
    i.c = i.c || '""';
    return g(i);
};
var v = function (e, t) {
    var i = [];
    for (var n = 0; n < e.length; n++) {
        var a = e[n];
        if (3 !== a.t) {
            var r = a.a;
            var s = a.c;
            var l = {
                t: 1,
                n: '"' + a.n + '"',
                g: undefined,
                v: undefined,
                id: undefined,
                cl: undefined,
                cpf: undefined,
                st: undefined,
                sl: undefined,
                sn: undefined,
                a: '',
                c: ''
            };
            if ('slot' === a.n) {
                l.v = true;
                l.sn = '""';
                s = [];
            } else {
                'block' !== a.n && 'virtual' !== a.n || (l.v = true);
            }
            var d = 0;
            var A = null;
            var c = [];
            var w = null;
            var m = false;
            var I = false;
            var b = false;
            var C = false;
            var y = Object.create(null);
            var E = [];
            var x = Object.create(null);
            var B = Object.create(null);
            if (r) {
                for (var S = 0; S < r.length; S++) {
                    var Q = r[S];
                    var k = Q.n;
                    if (!y[k])
                        if (y[k] = true, 'id' === k)
                            l.id = u(Q.v);
                        else if ('class' === k || 'class$' === k || 'class:' === k)
                            (w = _(Q.v, t)).e && (b = true), l.cl = g({
                                v: w.c,
                                e: w.e,
                                l: undefined,
                                b: w.b
                            });
                        else if ('style' === k || 'style$' === k || 'style:' === k)
                            (w = _(Q.v, t)).e && (C = true), l.st = g({
                                v: w.c,
                                e: w.e,
                                l: undefined,
                                b: w.b
                            });
                        else if ('slot' === k)
                            l.sl = u(Q.v);
                        else if ('name' === k && 'slot' === a.n)
                            l.sn = u(Q.v);
                        else if ('generic:' === k.slice(0, 8))
                            l.g = '', x[k.slice(8)] = u(Q.v);
                        else if ('filter:' === k.slice(0, 7))
                            l.cpf = '', B[k.slice(7)] = u(Q.v);
                        else if ('wx:' === k.slice(0, 3)) {
                            var D = k.slice(3);
                            if (!Object.prototype.hasOwnProperty.call(instruct, D))
                                throw new Error('Directive "' + D + '" is not found.');
                            var M = instruct[D].precompile(D, Q.v, t);
                            d += M.s.length;
                            t = t.concat(M.s);
                            var N = g({
                                s: JSON.stringify(M.s),
                                n: '"' + D + '"',
                                d: M.d,
                                l: M.l,
                                b: M.b
                            });
                            var T = instruct[D].addDefaultAttrs;
                            T && r.push.apply(r, T);
                            if (instruct[D].attachedToBlock)
                                c.push(N);
                            else if (instruct[D].requireBlock) {
                                if (null !== A)
                                    throw new Error('Uncompatible directives are used in a single element.');
                                A = N;
                            } else
                                E.push(N);
                        } else {
                            var R = {
                                n: '"' + Q.n + '"',
                                v: u(Q.v),
                                o: undefined,
                                e: undefined,
                                l: undefined,
                                b: undefined
                            };
                            if ('$' === k.slice(-1)) {
                                R.o = '"$"';
                                R.n = '"' + k.slice(0, -1) + '"';
                            } else {
                                if (':' === k.slice(-1)) {
                                    R.o = '":"';
                                    R.n = '"' + h(k.slice(0, -1)) + '"';
                                } else {
                                    if ('&' === k.slice(-1)) {
                                        R.o = '"&"';
                                        R.n = '"' + h(k.slice(0, -1)) + '"';
                                    } else {
                                        if ('class.' === k.slice(0, 6)) {
                                            R.o = '"c"';
                                            R.n = '"' + k.slice(6) + '"';
                                            m = true;
                                        } else {
                                            if ('style.' === k.slice(0, 6)) {
                                                R.o = '"s"';
                                                R.n = '"' + k.slice(6) + '"';
                                                I = true;
                                            } else {
                                                if ('data-' === k.slice(0, 5)) {
                                                    R.o = '"d"';
                                                    R.n = '"' + h(k.slice(5)) + '"';
                                                    m = true;
                                                };
                                            }
                                        }
                                    }
                                }
                            }
                            if ('id' === R.n || 'slot' === R.n)
                                throw new Error('"id" and "slot" do not support dynamic binding symbol.');
                            w = _(Q.v, t);
                            R.v = w.c;
                            R.e = w.e;
                            R.l = w.l;
                            R.b = w.b;
                            E.push(g(R));
                        }
                }
                if (b && m)
                    throw new Error('Class bindings cannot be used with dynamic class property.');
                if (C && I)
                    throw new Error('Style bindings cannot be used with dynamic style property.');
                l.a = p(E);
                l.c = v(s, t);
                '' === l.g && (l.g = g(x));
                '' === l.cpf && (l.cpf = g(B));
                if (A) {
                    if ('"block"' === l.n && '[]' === l.a) {
                        l.a = '[' + c.concat(A).join(',') + ']';
                        i.push(g(l));
                    } else {
                        i.push(g({
                            t: 1,
                            n: '"block"',
                            v: true,
                            a: '[' + c.concat(A).join(',') + ']',
                            c: '[' + g(l) + ']'
                        }));
                    }
                } else {
                    i.push(g(l));
                }
                t.splice(t.length - d, d);
            }
        } else
            i.push(f(a, t));
    }
    return p(i);
};
exports.compile = function (e) {
    var t = htmlParser.parse(e);
    var i = v(t, []);
    return 'function(' + c + '){return ' + i + '}';
};
